/*
 * Copyright 2014 Frakbot (Sebastiano Poggi and Francesco Pontillo)
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.supply.dl.widget.span;

import android.animation.ValueAnimator;
import android.os.Build;
import android.text.TextPaint;
import android.text.style.SuperscriptSpan;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.TextView;

import java.lang.ref.WeakReference;

/*package*/ final class JumpingBeansSpan extends SuperscriptSpan implements ValueAnimator.AnimatorUpdateListener
{

	private ValueAnimator jumpAnimator;
	private WeakReference<TextView> textView;
	private int shift;
	private int delay;
	private int loopDuration;
	private float animatedRange;

	public JumpingBeansSpan(TextView textView, int loopDuration, int position, int waveCharOffset,
			float animatedRange)
	{
		this.textView = new WeakReference<TextView>(textView);
		this.delay = waveCharOffset * position;
		this.loopDuration = loopDuration;
		this.animatedRange = animatedRange;
	}

	@Override
	public void updateMeasureState(TextPaint tp)
	{
		initIfNecessary(tp);
		tp.baselineShift = shift;
	}

	@Override
	public void updateDrawState(TextPaint tp)
	{
		initIfNecessary(tp);
		tp.baselineShift = shift;
	}

	private void initIfNecessary(TextPaint tp)
	{
		if (jumpAnimator != null)
		{
			return;
		}

		shift = (int) tp.ascent() / 2;
		jumpAnimator = ValueAnimator.ofInt(0, shift, 0);
		jumpAnimator.setDuration(loopDuration).setStartDelay(delay);
		jumpAnimator.setInterpolator(new JumpInterpolator(animatedRange));
		jumpAnimator.setRepeatCount(ValueAnimator.INFINITE);
		jumpAnimator.setRepeatMode(ValueAnimator.RESTART);
		jumpAnimator.addUpdateListener(this);
		jumpAnimator.start();
	}

	@Override
	public void onAnimationUpdate(ValueAnimator animation)
	{
		// No need for synchronization as this always run on main thread anyway
		TextView v = textView.get();
		if (v != null)
		{
			if (isAttachedToHierarchy(v))
			{
				Object obj = animation.getAnimatedValue();
				if (obj != null)
				{
					shift = Integer.parseInt(obj + "");
				}
				v.invalidate();
			}
			else
			{
//				animation.setCurrentPlayTime(0);
//				animation.start();
			}
		}
		else
		{
			// The textview has been destroyed and teardown() hasn't been called
			teardown();
		}
	}

	private boolean isAttachedToHierarchy(View v)
	{
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
		{
			return v.isAttachedToWindow();
		}
		else
		{
			return v.getParent() != null;   // Best-effort fallback
		}
	}

	/*package*/ void teardown()
	{
		if (jumpAnimator != null)
		{
			jumpAnimator.cancel();
			jumpAnimator.removeAllListeners();
		}
		if (textView.get() != null)
		{
			textView.clear();
		}
	}

	/**
	 * A tweaked {@link android.view.animation.AccelerateDecelerateInterpolator}
	 * that covers the full range in a fraction of its input range, and holds on
	 * the final value on the rest of the input range. By default, this fraction
	 * is half of the full range.
	 * @see com.ctalk.qmqzzs.widget.span.JumpingBeans#DEFAULT_ANIMATION_DUTY_CYCLE
	 */
	private class JumpInterpolator implements Interpolator
	{

		private float animRange;

		public JumpInterpolator(float animatedRange)
		{
			animRange = Math.abs(animatedRange);
		}

		@Override
		public float getInterpolation(float input)
		{
			if (input <= animRange)
			{
				return (float) (Math.cos((input / animRange + 1) * Math.PI) / 2f) + 0.5f;
			}
			return 1.0f;
		}
	}
}
